package com.tmpt.utils;

import java.nio.ByteBuffer;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.*;
import javax.crypto.spec.*;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.*;


public final class CryptoUtils {
	/**
	 * 功能：10进制串转为BCD码，暂时使用，以后去掉
	 * 
	 * @param byteSrc
	 *            asc码数组
	 * @return bcd码编码到的byte数组
	 */
	public static byte[] asc2bcd(byte[] byteSrc, int nLen) {
		return str2bcd(new String(byteSrc));
	}

	/**
	 * 功能：BCD码转为10进制串，暂时使用，以后去掉
	 * 
	 * @param byteSrc
	 *            bcd码数组
	 * @return 解码出来的asc码byte数组
	 */
	public static byte[] bcd2asc(byte[] byteSrc, int nLen) {
		return bcd2str(byteSrc).getBytes();
	}

	/**
	 * 功能：BCD码转为10进制串
	 * 
	 * @param byte[] bcd码编码的byte数组
	 * @return str 转化出来的字符串
	 */
	public static String bcd2str(byte[] bytes) {
		StringBuffer temp = new StringBuffer(bytes.length * 2);
		for (int i = 0; i < bytes.length; i++) {
			temp.append((byte) ((bytes[i] & 0xf0) >>> 4));
			temp.append((byte) (bytes[i] & 0x0f));
		}
		return temp.toString().substring(0, 1).equalsIgnoreCase("0") ? temp
				.toString().substring(1) : temp.toString();
	}

	/**
	 * 功能：byte数值数组转化成16进制字符字串
	 * 
	 * @param b
	 *            byte数组数据
	 * @return byte数值数组转化成16进制字符的字串
	 */
	public static String byte2hex(byte[] b) {
		String hs = "";
		String stmp = "";
		for (int i = 0; i < b.length; i++) {
			stmp = Integer.toHexString(b[i] & 0xFF);
			if (stmp.length() == 1) {
				hs += "0" + stmp;
			} else {
				hs += stmp;
			}
		}
		return hs.toUpperCase();
	}

	/**
	 * 散列算法
	 * 
	 * @param strAlgorithm
	 *            算法，"SHA-1"或"MD5"
	 * @param byteSource
	 *            需要散列计算的数据
	 * @return 经过散列计算的数据
	 * @throws NoSuchAlgorithmException
	 * @throws Exception
	 */
	public static byte[] doHash(String strAlgorithm, byte[] byteSource)
			throws NoSuchAlgorithmException {
		MessageDigest currentAlgorithm = MessageDigest
				.getInstance(strAlgorithm);
		// currentAlgorithm.reset();
		currentAlgorithm.update(byteSource);
		return currentAlgorithm.digest();
	}

	/**
	 * 散列算法
	 * 
	 * @param strAlgorithm
	 *            算法，"SHA-1"或"MD5"
	 * @param byteSource
	 *            需要散列计算的数据
	 * @return 经过散列计算的数据
	 * @throws NoSuchAlgorithmException
	 * @throws Exception
	 */
	public static String doHash(String strAlgorithm, String strSource)
			throws NoSuchAlgorithmException {
		MessageDigest currentAlgorithm = MessageDigest
				.getInstance(strAlgorithm);
		// currentAlgorithm.reset();
		currentAlgorithm.update(strSource.getBytes());
		return byte2hex(currentAlgorithm.digest());
	}

	// ===============RSA密钥对生成和签名校验==================
	/*
	 * 功能：生成证书私钥der编码数据，此2数据可以导出被存为文件
	 */
	public static KeyPair generateKeyPair(String strAlgorithm,
			Provider provider, int nKeySize) throws NoSuchAlgorithmException {
		/**** 生成证书，导出文件 ****/
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(
				strAlgorithm, provider);
		// final int KEY_SIZE = 1024;//没什么好说的了，这个值关系到块加密的大小，可以更改，但是不要太大，否则效率会低
		keyPairGen.initialize(nKeySize, new SecureRandom());
		return keyPairGen.genKeyPair();
	}

	/*
	 * 功能：从文件中取得私钥der编码数据，生成私钥对象
	 */
	public static PrivateKey getFilePrivateKey(String strAlgorithm,
			String strFilePath) throws NoSuchAlgorithmException, IOException,
			InvalidKeySpecException {
		KeyFactory kf = KeyFactory.getInstance(strAlgorithm);
		File file = new File(strFilePath);
		FileInputStream fis = new FileInputStream(file);
		byte bPrivateKey[] = new byte[(int) file.length()];
		BufferedInputStream bis = new BufferedInputStream(fis);
		if (bis.available() > 0) {
			bis.read(bPrivateKey);
		}
		bis.close();
		PKCS8EncodedKeySpec keySpecPrivate = new PKCS8EncodedKeySpec(
				bPrivateKey);
		return kf.generatePrivate(keySpecPrivate);
	}

	/*
	 * 功能：从文件中取得公钥der编码数据，生成公钥对象
	 */
	public static PublicKey getFilePublicKey(String strAlgorithm,
			String strFilePath) throws NoSuchAlgorithmException, IOException,
			InvalidKeySpecException {
		KeyFactory kf = KeyFactory.getInstance(strAlgorithm);
		File file = new File(strFilePath);
		FileInputStream fis = new FileInputStream(file);
		byte bPublicKey[] = new byte[(int) file.length()];
		BufferedInputStream bis = new BufferedInputStream(fis);
		if (bis.available() > 0) {
			bis.read(bPublicKey);
		}
		bis.close();
		X509EncodedKeySpec keySpecPublic = new X509EncodedKeySpec(bPublicKey);
		return kf.generatePublic(keySpecPublic);
	}

	/**
	 * 功能：16进制字符字串转化成byte数值数组
	 * 
	 * @param hex
	 *            16进制字符字串
	 * @return 16进制字符字串转化成byte数值的数组
	 */
	public static byte[] hex2byte(String hex) throws IllegalArgumentException {
		if (hex.length() % 2 != 0) {
			throw new IllegalArgumentException();
		}
		char[] arr = hex.toCharArray();
		byte[] b = new byte[hex.length() / 2];
		for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
			String swap = "" + arr[i++] + arr[i];
			int byteint = Integer.parseInt(swap, 16) & 0xFF;
			b[j] = new Integer(byteint).byteValue();
		}
		return b;
	}

	public static void main(String[] args) throws NoSuchAlgorithmException {
		String s = "helloworld";
		CryptoUtils c = new CryptoUtils();
		//.out.println("ss:" + c.doHash("MD5", s));

		/*
		 * String strKey = "22222222"; String strData = "3333333333333333";
		 * byte[] byteKey = com.lmx.util.ByteUtils.asc2num(strKey); byte[]
		 * byteData = com.lmx.util.ByteUtils.asc2num(strData);
		 * ////.out.println(strData);
		 * ////.out.println(com.lmx.util.ByteUtils.bcd2asc(byteData));
		 * for(int i=0;i<byteKey.length;++i) { ////.out.println(byteKey[i]);
		 * }
		 * 
		 * byte[] byteRet = null;//new byte[byteData.length]; byte[] byteRet1 =
		 * null; try { byteRet =
		 * CryptoUtils.symmetricEncrypto(byteKey,byteData); byteRet1 =
		 * CryptoUtils.symmetricDecrypto(byteKey,byteRet); } catch(Exception ex)
		 * { ex.printStackTrace(System.err); }
		 * //.out.println(byteRet.length);
		 * //.out.println(byteRet1.length); for(int
		 * i=0;i<byteRet.length;++i) { System.out.print(byteRet[i]);
		 * System.out.print(" " + Integer.toHexString(byteRet[i]) +" ");
		 * //.out.println(byteRet1[i]); }
		 */

		try {
			/*
			 * String strRet1 =
			 * CryptoUtils.tripleDESDecrypt("1ZVasdJJco1qccDnnfQfb8QeaARxhkR6",
			 * "A3F2569DESJEIWBCJOTY45DYQWF68H1Y");
			 * //.out.println("strRet1:"+strRet1);
			 */
			/*
			 * String pToEncrypt="!)*637"; String
			 * sKey="012345678912345612345678"; String sIV="12345678"; String
			 * strRet = CryptoUtils.tripleDESEncrypt(pToEncrypt, sKey);
			 * //.out.println("strRet:"+strRet); String strRet1 =
			 * CryptoUtils.tripleDESDecrypt(strRet, sKey);
			 * //.out.println("strRet1:"+strRet1);
			 */

			long lngID = 131991;
			String strPassword = "123456";
			String strEncodePWD = CryptoUtils.verifyEncode(lngID, strPassword);
			//.out.println(strEncodePWD);
			/*
			 * //MD5出来的结果是128bit的大整数，占用16个字节(每个字节8bit，所以是816=128bit) byte[]
			 * byteRet = CryptoUtils.doHash("MD5", "11111111".getBytes());
			 * //.out.println(byteRet.length);
			 * 
			 * String strRet = CryptoUtils.doHash("MD5", "11111111");
			 * //.out.println(strRet); //.out.println(strRet.length());
			 * 
			 * strRet = CryptoUtils.doHash("MD5", "1390000000015000");
			 * //.out.println(strRet);
			 * 
			 * strRet = CryptoUtils.doHash("MD5", "902902rt258456");
			 * //.out.println("902902rt258456"); //.out.println(strRet);
			 * 
			 * byte[] byteRet1 =
			 * CryptoUtils.symmetricEncrypto("11111111".getBytes(),
			 * "222222223333333344444444".getBytes()); //.out.println(new
			 * String(byteRet1)); //.out.println(byteRet1.length);
			 * 
			 * byte[] byteRet2 = CryptoUtils.str2bcd("02");
			 * //.out.println(byteRet2[0]);
			 * //.out.println(byteRet2.length);
			 * 
			 * byte[] byteRet3 = {0x2F,0x0F}; //byte[] byteRet3 = {0x0F,0x02};
			 * //byte[] byteRet3 = {0x00,0x02,0x0F,0x0F}; //byte[] byteRet3 =
			 * {0x0F,0x0F,0x00,0x02}; //.out.println(new String(byteRet3));
			 * //.out.println(byteRet3.length);
			 */
			/*
			 * String strAlgorithm = "RSA"; Provider provider = new
			 * org.bouncycastle.jce.provider.BouncyCastleProvider();
			 * 
			 * byte[] privateKeyBytes = null; byte[] publicKeyBytes = null;
			 * KeyPair keyPair = CryptoUtils.generateKeyPair(strAlgorithm,
			 * provider, 1024); privateKeyBytes =
			 * keyPair.getPrivate().getEncoded(); publicKeyBytes =
			 * keyPair.getPublic().getEncoded();
			 * FileUtils.logOnce("C:/test.key",privateKeyBytes);
			 * FileUtils.logOnce("C:/test.der",publicKeyBytes);
			 * 
			 * PublicKey publicKey = CryptoUtils.getFilePublicKey(strAlgorithm,
			 * "C:/test.der"); PrivateKey privateKey =
			 * CryptoUtils.getFilePrivateKey(strAlgorithm, "C:/test.key");
			 * 
			 * String myinfo =
			 * "12345678asdfasdfadsfasdvfasdvvcszxvvdsadfasfsdafa用他私人密钥(prikey)对他所确认的信息(info)进行数字签名产生一个签名数组12345678asdfasdfadsfasdvfasdvvcszxvvdsadfasfsdafa用他私人密钥(prikey)对他所确认的信息(info)进行数字签名产生一个签名数组"
			 * ; byte[] signed = CryptoUtils.sign("MD5withRSA", provider,
			 * privateKey, myinfo.getBytes()); //.out.println(
			 * CryptoUtils.verifySign("MD5withRSA", provider, publicKey,
			 * myinfo.getBytes(), signed) );
			 */

			/*
			 * String strAlgorithm = "RSA"; Provider provider = new
			 * org.bouncycastle.jce.provider.BouncyCastleProvider();
			 * 
			 * byte[] privateKeyBytes = null; KeyFactory kf =
			 * KeyFactory.getInstance("RSA"); //String strPrivateKeyPath =
			 * "D:/cert/CNCA_Server_UCINFO.der"; //File file = new
			 * File(strPrivateKeyPath); //FileInputStream fis = new
			 * FileInputStream(file); //byte bPrivateKey[] = new
			 * byte[(int)file.length()]; //BufferedInputStream bis = new
			 * BufferedInputStream(fis); //if (bis.available() > 0) {
			 * //bis.read(bPrivateKey); //} //bis.close(); String strPrivateKey
			 * =
			 * "MIICWwIBAAKBgQDbPlPiZW5ztXih1mjEwyiJcRUZ2JcSro5I+khIXY9mqsHKtAMg0Y9EdOPaFMSX+FAfqXsSUjGvB4dhqM9nSATrWokHix3McVoRiWbat76PFC4/0dLt5+4GSdGVPxvlofe8IBu/76+MfABnco+hIrUKhvbd6w0e7QqkRXfGLEv9qwIDAQABAoGATCL18I428DnZ/aG+2m3HmwtJP6OGuzchNFiuV2seTJIKIIGpAHGl5ikNo4NIzlmuQYCSu8cNd/IOYqzD8eMBybEoYQIlVeetCyMHf3qkqz7n3I7jiqQqhH9OnwGmRUY9N01BeUon5IW6DykexryNtZnzwMqpL7vew+iiQFUW/jkCQQDtLGA7qoCgGoKcSV6nNo6Wd23i/2cDNRv/4QQoM5uHwiCPoq/5ZKW5TavBfco7ujSnV8t8Ah/E7ugofGz/nWkNAkEA7KWYzi5a0o28b589QKN4tNdBQpdalBTc0LoK8HJDDiJsWZVviCLOCoMTTXpcOYDp1PFYTbQIHBQLIMVM919jlwJAXKMem2+HegGgzmah//IBU6gmVamolMoju5gqRYGS2D3s9e13ipPTX0OFOLhnS1j5w/s40aEKw6MFLvsan+Td6QJAZOJ30TYby/VWpvNo5nyKQfYeQShLGiQGuwkFDtp3UbhFHq/BO3UzB3I3sWj/lhgqF3jIH2AnsOiukcrq8+57gwJAImfX9VNNyTFgleKTJjvHq2n9bYo8vPmI43Dxqi/saAF9a5qAvmskLmnOQ28RQEurFpNF6QG2ezYEzLZWKVWCeQ=="
			 * ; byte bPrivateKey[] =
			 * Base64.decode(strPrivateKey);//CryptoUtils.
			 * hex2byte(strPrivateKey); PKCS8EncodedKeySpec keySpecPrivate = new
			 * PKCS8EncodedKeySpec(bPrivateKey); PrivateKey privateKey =
			 * kf.generatePrivate(keySpecPrivate); privateKeyBytes =
			 * privateKey.getEncoded();
			 * FileUtils.logOnce("C:/CNCA_Server_UCINFO.key",privateKeyBytes);
			 * 
			 * privateKey = CryptoUtils.getFilePrivateKey(strAlgorithm,
			 * "C:/CNCA_Server_UCINFO.key");
			 * 
			 * String myinfo =
			 * "12345678asdfasdfadsfasdvfasdvvcszxvvdsadfasfsdafa用他私人密钥(prikey)对他所确认的信息(info)进行数字签名产生一个签名数组12345678asdfasdfadsfasdvfasdvvcszxvvdsadfasfsdafa用他私人密钥(prikey)对他所确认的信息(info)进行数字签名产生一个签名数组"
			 * ; byte[] signed = CryptoUtils.sign("MD5withRSA", provider,
			 * privateKey, myinfo.getBytes());
			 */
		} catch (Exception e) {
			e.printStackTrace(System.out);
		}

	}

	/*
	 * public static String tripleDESDecrypt(String pToDecrypt, String sKey,
	 * String sIV) throws Exception {
	 * //.out.println("pToDecrypt:"+pToDecrypt+" sKey:"+sKey+" sIV:"+sIV);
	 * BASE64Decoder base64 = new BASE64Decoder(); byte[] bytesrc =
	 * base64.decodeBuffer(pToDecrypt); //byte[] bytesrc =
	 * pToDecrypt.getBytes(); //.out.println("bytesrc len:"+bytesrc.length);
	 * Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); DESKeySpec
	 * desKeySpec = new DESKeySpec(sKey.getBytes("UTF-8")); SecretKeyFactory
	 * keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey =
	 * keyFactory.generateSecret(desKeySpec); IvParameterSpec iv = new
	 * IvParameterSpec(sIV.getBytes("UTF-8"));
	 * 
	 * cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
	 * 
	 * byte[] retByte = cipher.doFinal(bytesrc); return new String(retByte); }
	 */
	// ==============与C#对接的3DS加解密算法(不过中文会有问题)<end>=====================
	/*******
	 * 功能：环天圣地系统编码
	 * 
	 * @throws NoSuchAlgorithmException
	 * */
	public static String verifyEncode(long lngID, String strPassword)
			throws NoSuchAlgorithmException {
		StringBuilder sb = new StringBuilder();
		// 1)添加[ID值*2+119]
		// 2)添加密码
		// 3)添加[虚无缥缈月华如盖]
		// 4)进行MD5算法，得到签名串
		sb.append(lngID * 2 + 119).append(strPassword).append("虚无缥缈，月华如盖。");
		String strContent = sb.toString();
		String strMD5 = CryptoUtils.doHash("MD5", strContent);
		// //.out.println("第1次MD5的内容："+strContent);
		// //.out.println("第1次MD5的结果："+strMD5);
		// 5)反转签名串
		// 6)添加[万里江山万里晴]
		// 7)再做MD5算法
		sb.setLength(0);
		sb.append(strMD5);
		sb.reverse();
		sb.append("万里江山万里晴，一缕尘心一缕烟。");
		strContent = sb.toString();
		strMD5 = CryptoUtils.doHash("MD5", strContent);
		// //.out.println("第2次MD5的内容："+strContent);
		// //.out.println("第2次MD5的结果："+strMD5);
		// 8)将上次的MD5值分成两份
		// 9)再分别做MD5算法
		// 10)合并两份的值
		String strContent1 = strMD5.substring(0, 5);
		String strContent2 = strMD5.substring(5);
		strContent = strContent1;
		strMD5 = CryptoUtils.doHash("MD5", strContent);
		sb.setLength(0);
		sb.append(strMD5);
		// //.out.println("第3次MD5的内容："+strContent);
		// //.out.println("第3次MD5的结果："+strMD5);
		strContent = strContent2;
		strMD5 = CryptoUtils.doHash("MD5", strContent);
		sb.append(strMD5);
		// //.out.println("第4次MD5的内容："+strContent);
		// //.out.println("第4次MD5的结果："+strMD5);
		// 11)对所得的值再做一次MD5算法
		strContent = sb.toString();
		strMD5 = CryptoUtils.doHash("MD5", strContent);
		// //.out.println("第5次MD5的内容："+strContent);
		// //.out.println("第5次MD5的结果："+strMD5);

		return strMD5;
	}

	/*
	 * 功能：用私钥对信息签名
	 */
	public static byte[] sign(String strAlgorithm, Provider provider,
			PrivateKey privateKey, byte[] btSignedData)
			throws NoSuchAlgorithmException, InvalidKeyException,
			SignatureException {
		// 初始一个Signature对象,并用私钥对信息签名
		Signature signet = Signature.getInstance(
				strAlgorithm, provider);

		signet.initSign(privateKey);
		signet.update(btSignedData);
		return signet.sign();
	}

	/*
	 * 功能：用私钥对信息签名
	 */
	public static String sign(String strAlgorithm, Provider provider,
			PrivateKey privateKey, String strSignedData)
			throws NoSuchAlgorithmException, InvalidKeyException,
			SignatureException {
		// 初始一个Signature对象,并用私钥对信息签名
		Signature signet = Signature.getInstance(
				strAlgorithm, provider);

		signet.initSign(privateKey);
		signet.update(strSignedData.getBytes());
		return byte2hex(signet.sign());
	}

	/**
	 * 签名
	 * 
	 * @param strKeyStorePath
	 *            keystore文件路径
	 * @param strKeyStorePass
	 *            keystore密码
	 * @param strPKIAlias
	 *            密钥对的别名
	 * @param strPKIPass
	 *            提取私钥的密码
	 * @param byteSource
	 *            需要被签名的数据
	 * @param algorithm
	 *            签名算法
	 * @return 经过签名计算的数据
	 * @throws Exception
	 */
	public static byte[] signByKeyStore(String strKeyStorePath,
			String strKeyStorePass, String strPKIAlias, String strPKIPass,
			byte[] byteSource, String algorithm) throws Exception {
		// 检测系统是否已加载此Provider的方法
		if (null == Security.getProvider("BC")) {
			// 加载Provider
			Security.addProvider(new BouncyCastleProvider());
		}

		try {
			// 从密钥库中直接读取证书
			FileInputStream in = new FileInputStream(strKeyStorePath);
			KeyStore ks = KeyStore.getInstance("JKS");
			ks.load(in, strKeyStorePass.toCharArray());
			// 从密钥库中读取CA的私钥
			PrivateKey myprikey = (PrivateKey) ks.getKey(strPKIAlias,
					strPKIPass.toCharArray());
			// 用他私人密钥(prikey)对他所确认的信息(info)进行数字签名产生一个签名数组
			// 初始一个Signature对象,并用私钥对信息签名
			Signature signet = Signature
					.getInstance(algorithm, "BC");
			signet.initSign(myprikey);
			signet.update(byteSource);
			return signet.sign();
		} catch (Exception e) {
			throw e;
		}
	}

	/**
	 * 功能：10进制串转为BCD码
	 * 
	 * @param str
	 *            待转的字符串
	 * @return bcd码编码到的byte数组
	 */
	public static byte[] str2bcd(String str) {
		if (str.length() % 2 != 0)
			str = "0" + str;

		StringBuffer sb = new StringBuffer(str);
		ByteBuffer bb = ByteBuffer.allocate(str.length() / 2);

		int i = 0;
		while (i < str.length()) {
			bb
					.put((byte) ((Integer.parseInt(sb.substring(i, i + 1))) << 4 | Integer
							.parseInt(sb.substring(i + 1, i + 2))));
			i = i + 2;
		}
		return bb.array();
	}

	/**
	 * DES对称解密方法
	 * 
	 * @param byteSource
	 *            需要解密的数据
	 * @return 经过解密的数据
	 * @throws Exception
	 */
	public static byte[] symmetricDecrypto(byte[] keyData, byte[] byteSource)
			throws Exception {
		// 检测系统是否已加载此Provider的方法
		if (null == Security.getProvider("BC")) {
			// 加载Provider
			Security.addProvider(new BouncyCastleProvider());
		}

		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		int mode = Cipher.DECRYPT_MODE;
		try {
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES",
					"BC");
			DESKeySpec keySpec = new DESKeySpec(keyData);
			Key key = keyFactory.generateSecret(keySpec);
			Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding", "BC");
			cipher.init(mode, key);

			CipherOutputStream cOut = new CipherOutputStream(baos, cipher);
			cOut.write(byteSource);
			cOut.close();
			return baos.toByteArray();
		} catch (Exception e) {
			throw e;
		} finally {
			baos.close();
		}
	}

	/**
	 * DES对称加密方法
	 * 
	 * @param byteSource
	 *            需要加密的数据
	 * @return 经过加密的数据
	 * @throws Exception
	 */
	public static byte[] symmetricEncrypto(byte[] keyData, byte[] byteSource)
			throws Exception {
		// 检测系统是否已加载此Provider的方法
		if (null == Security.getProvider("BC")) {
			// 加载Provider
			Security.addProvider(new BouncyCastleProvider());
		}

		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		int mode = Cipher.ENCRYPT_MODE;
		try {
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES",
					"BC");
			DESKeySpec keySpec = new DESKeySpec(keyData);
			Key key = keyFactory.generateSecret(keySpec);
			Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding", "BC");
			cipher.init(mode, key);

			// 必须用下面Stream实现，用原cipher.update和doFinal方法加密还是会在后面Padding内容。
			CipherOutputStream cOut = new CipherOutputStream(baos, cipher);
			cOut.write(byteSource);
			cOut.close();
			return baos.toByteArray();
		} catch (Exception e) {
			throw e;
		} finally {
			baos.close();
		}
	}

	/**
	 * 3DS解密
	 * 
	 * @param pToEncrypt
	 *            待解密的源数据(BASE64格式)
	 * @param sKey
	 *            密钥，长度必须是8的倍数
	 * @param sIV
	 *            长度是8
	 * @return 返回解密后的原始数据
	 * @throws Exception
	 */
	public static String tripleDESDecrypt(String pToDecrypt, String sKey)
			throws Exception {
		// //.out.println("pToDecrypt:"+pToDecrypt+" sKey:"+sKey);
		BASE64Decoder base64 = new BASE64Decoder();
		byte[] bytesrc = base64.decodeBuffer(pToDecrypt);
		Cipher cipher = Cipher.getInstance("DESede");
		// DESKeySpec desKeySpec = new DESKeySpec(sKey.getBytes("UTF-8"));
		// DESKeySpec desKeySpec = new DESKeySpec(base64.decodeBuffer(sKey));
		// SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		// SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
		SecretKey secretKey = new SecretKeySpec(sKey
				.getBytes("UTF-8"), "DESede");

		cipher.init(Cipher.DECRYPT_MODE, secretKey);

		byte[] retByte = cipher.doFinal(bytesrc);
		return new String(retByte);
	}

	// ==============与C#对接的3DS加解密算法(不过中文会有问题)<begin>=====================
	/**
	 * 3DS加密
	 * 
	 * @param pToEncrypt
	 *            待加密的源数据
	 * @param sKey
	 *            密钥，长度必须是8的倍数
	 * @param sIV
	 *            长度是8
	 * @return 返回加密后的数据(BASE64格式)
	 * @throws Exception
	 */
	public static String tripleDESEncrypt(String pToEncrypt, String sKey)
			throws Exception {
		byte[] bytesrc = pToEncrypt.getBytes();
		Cipher cipher = Cipher.getInstance("DESede");
		// DESKeySpec desKeySpec = new DESKeySpec(sKey.getBytes("UTF-8"));
		// SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		// SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
		SecretKey secretKey = new SecretKeySpec(sKey
				.getBytes("UTF-8"), "DESede");

		cipher.init(Cipher.ENCRYPT_MODE, secretKey);

		byte[] retByte = cipher.doFinal(bytesrc);
		BASE64Encoder base64 = new BASE64Encoder();
		return base64.encode(retByte);
	}

	/**
	 * 校验签名
	 * 
	 * @param strKeyStorePath
	 *            keystore文件路径
	 * @param strKeyStorePass
	 *            keystore密码
	 * @param strPKIAlias
	 *            密钥对的别名
	 * @param byteSource
	 *            被签名的数据
	 * @param byteSigned
	 *            需要被校验的签名
	 * @param algorithm
	 *            签名算法
	 * @return 验证签名的结果
	 * @throws Exception
	 */
	public static boolean verifyByKeyStore(String strKeyStorePath,
			String strKeyStorePass, String strPKIAlias, byte[] byteSource,
			byte[] byteSigned, String algorithm) throws Exception {
		// 检测系统是否已加载此Provider的方法
		if (null == Security.getProvider("BC")) {
			// 加载Provider
			Security.addProvider(new BouncyCastleProvider());
		}

		try {
			// 从密钥库中直接读取证书
			FileInputStream in = new FileInputStream(strKeyStorePath);
			KeyStore ks = KeyStore.getInstance("JKS");
			ks.load(in, strKeyStorePass.toCharArray());
			// 从密钥库中读取证书
			java.security.cert.Certificate c1 = ks.getCertificate(strPKIAlias);
			// 初始一个Signature对象,并用证书对签名作校验
			Signature signet = Signature
					.getInstance(algorithm, "BC");
			signet.initVerify(c1);
			signet.update(byteSource);
			return signet.verify(byteSigned);
		} catch (Exception e) {
			throw e;
		}
	}

	/**
	 * 校验散列值
	 * 
	 * @param strAlgorithm
	 *            算法，"SHA-1"或"MD5"
	 * @param byteSource
	 *            需要散列计算的数据
	 * @param byteHash
	 *            需要验证的散列数据
	 * @return 校验结果true或false
	 * @throws NoSuchAlgorithmException
	 * @throws Exception
	 */
	public static boolean verifyHash(String strAlgorithm, byte[] byteSource,
			byte[] byteHash) throws NoSuchAlgorithmException {
		MessageDigest alga = MessageDigest
				.getInstance(strAlgorithm);
		alga.update(byteSource);
		byte[] digesta = alga.digest();
		if (MessageDigest.isEqual(digesta, byteHash)) {
			return true;
		} else {
			return false;
		}
	}

	/*
	 * public static String tripleDESEncrypt(String pToEncrypt, String sKey,
	 * String sIV) throws Exception { byte[] bytesrc = pToEncrypt.getBytes();
	 * Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); DESKeySpec
	 * desKeySpec = new DESKeySpec(sKey.getBytes("UTF-8")); SecretKeyFactory
	 * keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey =
	 * keyFactory.generateSecret(desKeySpec); IvParameterSpec iv = new
	 * IvParameterSpec(sIV.getBytes("UTF-8"));
	 * 
	 * cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
	 * 
	 * byte[] retByte = cipher.doFinal(bytesrc); BASE64Encoder base64 = new
	 * BASE64Encoder(); return base64.encode(retByte); }
	 */

	/**
	 * 校验散列值
	 * 
	 * @param strAlgorithm
	 *            算法，"SHA-1"或"MD5"
	 * @param strSource
	 *            需要散列计算的文本数据
	 * @param strHexHash
	 *            需要验证的散列数据，16进制字串表示
	 * @return 校验结果true或false
	 * @throws NoSuchAlgorithmException
	 * @throws Exception
	 */
	public static boolean verifyHash(String strAlgorithm, String strSource,
			String strHexHash) throws NoSuchAlgorithmException {
		MessageDigest alga = MessageDigest
				.getInstance(strAlgorithm);
		alga.update(strSource.getBytes());
		byte[] digesta = alga.digest();
		if (MessageDigest.isEqual(digesta, hex2byte(strHexHash))) {
			return true;
		} else {
			return false;
		}
	}

	/*
	 * 功能：用公钥对签名信息进行校验
	 */
	public static boolean verifySign(String strAlgorithm, Provider provider,
			PublicKey publicKey, byte[] btSignedData, byte[] btDigest)
			throws NoSuchAlgorithmException, InvalidKeyException,
			SignatureException {
		// 初始一个Signature对象,并用私钥对信息签名
		Signature signet = Signature.getInstance(
				strAlgorithm, provider);

		signet.initVerify(publicKey);
		signet.update(btSignedData);
		return signet.verify(btDigest);
	}

	/*
	 * 功能：用公钥对签名信息进行校验
	 */
	public static boolean verifySign(String strAlgorithm, Provider provider,
			PublicKey publicKey, String strSignedData, String strDigest)
			throws NoSuchAlgorithmException, InvalidKeyException,
			SignatureException {
		// 初始一个Signature对象,并用私钥对信息签名
		Signature signet = Signature.getInstance(
				strAlgorithm, provider);

		signet.initVerify(publicKey);
		signet.update(strSignedData.getBytes());
		return signet.verify(hex2byte(strDigest));
	}

}
